﻿Imports System.Configuration
Imports MostRecentlyUsed.My

''' <summary>
''' Stores a list of recently used strings.
''' </summary>
    Friend Class RecentlyUsedItems
    Implements IEnumerable

#Region "instance variables"

    Private ReadOnly m_iMaxItemsToCache As Integer
    Private ReadOnly m_eProjectType As Helper.ProjectType
    Private ReadOnly m_eRecentType As Helper.RecentType
    Private ReadOnly m_szListName As String
    Private Const DELIMITER As String = ";"

#End Region

#Region "properties"

#Region "List"

    Private ReadOnly m_oRuiDictionary As List(Of String)

    Private ReadOnly Property RecentlyUsedItemsList As List(Of String)
        Get
            Return m_oRuiDictionary
        End Get
    End Property

#End Region

#End Region

#Region "RecentlyUsedItems Constructor(s)"

    ''' <summary>
    ''' Initializes a new instance of the <see cref="RecentlyUsedItems"/> class.
    ''' </summary>
    ''' <param name="eProjectType">project type</param>
    ''' <param name="eRecentType">Recent type of item</param>
    ''' <param name="szListName">Recently Used RecentlyUsedItemsList List name</param>
    ''' <param name="iMaxItemsToCache">max items to cache</param>
    Public Sub New(eProjectType As Helper.ProjectType, eRecentType As Helper.RecentType, szListName As String, iMaxItemsToCache As Integer)
        m_eProjectType = eProjectType
        m_eRecentType = eRecentType
        m_iMaxItemsToCache = iMaxItemsToCache
        m_szListName = szListName

        Dim szSettingName As String = GetSettingName(eProjectType, eRecentType, szListName)

        Dim szProjectMRU As String
        Try
            szProjectMRU = Settings(szSettingName).ToString()
        Catch
            AddProperty(szSettingName, String.Empty, GetType(String))
            Settings.Save()
            Settings.Reload()
            szProjectMRU = Settings(szSettingName).ToString()
        End Try

        m_oRuiDictionary = New List(Of String)()
        For Each szEntry As String In szProjectMRU.Split({DELIMITER}, StringSplitOptions.RemoveEmptyEntries)
            Dim szPath As String = szEntry.Split({"|"c}, 2, StringSplitOptions.RemoveEmptyEntries)(0)
            szPath = Environment.ExpandEnvironmentVariables(szPath)
            If (Path.IsPathRooted(szPath)) Then
                m_oRuiDictionary.Add(szEntry)
            End If
        Next

        'm_oRuiDictionary = New List(Of String)(szProjectMRU.Split({m_cDelimiter}, StringSplitOptions.RemoveEmptyEntries))
    End Sub

#End Region

#Region "Remove"

    ''' <summary>
    ''' Removes the specified item from the RUI list.
    ''' </summary>
    ''' <param name="szItemToRemove">item to remove</param>
    ''' <returns>true if the item was found and removed, false if item did not exist.</returns>
    Public Function Remove(szItemToRemove As String) As Boolean
        szItemToRemove = ValidateItem(szItemToRemove, "szItemToRemove")

        If RecentlyUsedItemsList.Contains(szItemToRemove) Then
            RecentlyUsedItemsList.Remove(szItemToRemove)

            Dim szSettingName As String = GetSettingName(m_eProjectType, m_eRecentType, m_szListName)
            Settings(szSettingName) = String.Join(DELIMITER, RecentlyUsedItemsList)

            Settings.Save()
            Return True
        Else
            Return False

        End If
    End Function

#End Region

#Region "AddOrUpdate"

    ''' <summary>
    ''' Adds an item to the RUI list 
    ''' or updates the item by moving it to the top of the list.
    ''' </summary>
    ''' <param name="szItemToAdd">item to add</param>
    ''' <returns>boolean as to whether the item was added (didn't previously exist in collection)</returns>
    Public Function AddOrUpdate(szItemToAdd As String) As Boolean
        szItemToAdd = ValidateItem(szItemToAdd, "szItemToAdd")
        Dim bAdded As Boolean = (False = Contains(szItemToAdd))

        If Not RecentlyUsedItemsList.Contains(szItemToAdd) Then
            RecentlyUsedItemsList.Insert(0, szItemToAdd)
        Else
            RecentlyUsedItemsList.Remove(szItemToAdd)
            RecentlyUsedItemsList.Insert(0, szItemToAdd)
        End If

        ' remove entries that fell off the list.
        If RecentlyUsedItemsList.Count > m_iMaxItemsToCache Then
            RecentlyUsedItemsList.RemoveRange(m_iMaxItemsToCache, RecentlyUsedItemsList.Count - m_iMaxItemsToCache)
        End If

        Dim szSettingName As String = GetSettingName(m_eProjectType, m_eRecentType, m_szListName)
        Settings(szSettingName) = String.Join(DELIMITER, RecentlyUsedItemsList)

        Settings.Save()
        Return bAdded
    End Function

#End Region

#Region "Contains"

    ''' <summary>
    ''' Determines whether the specified items already exists in the recently used list
    ''' </summary>
    ''' <param name="szItem">item</param>
    ''' <returns>
    ''' 	<c>true</c> if [contains] [the specified sz item]; otherwise, <c>false</c>.
    ''' </returns>
    Public Function Contains(szItem As String) As Boolean
        Return RecentlyUsedItemsList.Contains(szItem)
    End Function

#End Region

#Region "Implementation of IEnumerable"

    ''' <summary>
    ''' Returns an enumerator that iterates through a collection.
    ''' </summary>
    ''' <returns>
    ''' An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
    ''' </returns>
    ''' <filterpriority>2</filterpriority>
    Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
        Return RecentlyUsedItemsList.GetEnumerator()
    End Function

#End Region

#Region "this"

    ''' <summary>
    ''' Gets the <see cref="System.String"/> with the specified index
    ''' </summary>
    ''' <value></value>
    Default Public ReadOnly Property Item(iIndex As Integer) As String
        Get
            Return RecentlyUsedItemsList(iIndex)
        End Get
    End Property

#End Region

#Region "private methods"

    Private Function ValidateItem(szItem As String, szParameterName As String) As String
        Dim szItemToValidate As String = szItem.Trim()
        If (szItemToValidate Is Nothing) OrElse (szItem.Length = 0) Then
            Throw New ArgumentNullException(szParameterName)
        End If
        Return szItemToValidate
    End Function

    Private Function GetSettingName(eProjectType As Helper.ProjectType, eRecentType As Helper.RecentType, szListName As String) As String
        Select Case eProjectType
            Case Helper.ProjectType.VisualStudio
                Select Case eRecentType
                    Case Helper.RecentType.Project
                        Return "VSProj_" & szListName
                    Case Helper.RecentType.File
                        Return "VSFile_" & szListName
                    Case Else
                        Throw New ArgumentException("Recent project type not recognized: " & eRecentType)
                End Select
            Case Helper.ProjectType.SqlServerManagementStudio
                Select Case eRecentType
                    Case Helper.RecentType.Project
                        Return "SSMSProj_" & szListName
                    Case Helper.RecentType.File
                        Return "SSMSFile_" & szListName
                    Case Else
                        Throw New ArgumentException("Recent project type not recognized: " & eRecentType)
                End Select
            Case Else
                Throw New ArgumentException("Project type not recognized: " & eProjectType)
        End Select
    End Function

    Private Sub AddProperty(ByVal propertyName As String, ByVal defaultValue As String, ByVal propertyType As Type)
        Const PROVIDER_NAME As String = "LocalFileSettingsProvider"

        Dim oSettingsAttributeDictionary As New SettingsAttributeDictionary()
        Dim oUserScopedSettingAttribute As New UserScopedSettingAttribute()
        oSettingsAttributeDictionary.Add(oUserScopedSettingAttribute.TypeId(), oUserScopedSettingAttribute)
        Dim _
            oProperty As _
                New SettingsProperty(New SettingsProperty(propertyName, propertyType, MySettings.Default.Providers(PROVIDER_NAME), False, defaultValue, SettingsSerializeAs.String,
                                                          oSettingsAttributeDictionary, False, False))

        MySettings.Default.Properties.Add(oProperty)
    End Sub

#End Region

End Class
